package com.atguigu.daijia.common.feign;

import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.Result;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import feign.FeignException;
import feign.Response;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;

import java.io.IOException;
import java.lang.reflect.Type;

/**
 * 自定义Feign数据解码器
 * 继承自Decoder接口，用于在Feign调用后对响应数据进行解码
 */
public class FeignCustomDataDecoder implements Decoder {

    private final SpringDecoder decoder;

    public FeignCustomDataDecoder(SpringDecoder decoder) {
        this.decoder = decoder;
    }

    /**
     * 解码响应数据
     * 首先使用SpringDecoder进行解码，然后检查解码结果是否为null以及是否为预期的成功结果
     *
     * @param response 响应对象
     * @param type     目标类型
     * @return 解码后的对象
     * @throws IOException       如果发生IO异常
     * @throws DecodeException   如果数据解码失败
     * @throws FeignException    如果Feign调用失败
     */
    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        // 使用SpringDecoder进行解码
        Object decode = this.decoder.decode(response, type);
        // 如果解码结果为null，则抛出解码异常
        if (decode == null) {
            throw new DecodeException(ResultCodeEnum.FEIGN_FAIL.getCode(), ResultCodeEnum.FEIGN_FAIL.getMessage(), response.request()); // 数据解析失败
        }

        // 如果解码结果是Result类型，则进一步检查结果码和数据
        if (decode instanceof Result<?>) {
            Result<?> result = (Result<?>) decode;

            // 判断状态码是否为200
            if (result.getCode().intValue() != ResultCodeEnum.SUCCESS.getCode().intValue()) {
                throw new DecodeException(result.getCode(), result.getMessage(), response.request());
            }
            // 判断数据是否为null
            if (null == result.getData()) {
                throw new DecodeException(ResultCodeEnum.FEIGN_FAIL.getCode(), ResultCodeEnum.FEIGN_FAIL.getMessage(), response.request());
            }
            return result;
        }
        return decode;
    }
}
